﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;

namespace PSE.Deployment.Util
{
    public class WindowsRegistry
    {
        /// <summary>
        /// Entity that represents information installation and uninstallation
        /// </summary>
        public class InstalledInformation
        {
            /// <summary>
            /// Displayed Name into Add/Remove Programs
            /// </summary>
            public string DisplayName { get; set; }

            /// <summary>
            /// Uninstal Path
            /// </summary>
            public string UninstallString { get; set; }

            /// <summary>
            /// Icon Path
            /// </summary>
            public string DisplayIcon { get; set; }

            /// <summary>
            /// Location Path
            /// </summary>
            public string InstallLocation { get; set; }

            /// <summary>
            /// Location Source
            /// </summary>
            public string InstallSource { get; set; }

            /// <summary>
            /// Parameters File Path
            /// </summary>
            public string ParametersFilePath { get; set; }

            /// <summary>
            /// System Version
            /// </summary>
            public string DisplayVersion { get; set; }

            /// <summary>
            /// Indicates whether you can modify the system setup by the installation
            /// </summary>
            public bool NoModify { get; set; }

            /// <summary>
            /// Indicates whether you can remove the system setup by the installation
            /// </summary>
            public bool NoRemove { get; set; }

            /// <summary>
            /// Indicates whether you can repair the system setup by the installation
            /// </summary>
            public bool NoRepair { get; set; }
        }

        public const string REGISTRY_UNINSTALL_PATH = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\";

        public static bool KeyExists(string key, RegistryKey baseGroupKey)
        {
            RegistryKey registryKey = null;
            bool keyExists = false;

            try
            {
                registryKey = baseGroupKey.OpenSubKey(key);
                keyExists = (registryKey != null);
            }
            catch
            {
                keyExists = false;
            }
            finally
            {
                if (registryKey != null)
                    registryKey.Close();
            }

            return keyExists;
        }

        public static bool StringKeyExists(string subKey, string stringKey, RegistryKey baseGroupKey)
        {

            string registryStringKey = "";
            bool keyExists = true;

            try
            {
                RegistryKey key = baseGroupKey.CreateSubKey(subKey);
                registryStringKey = key.GetValue(stringKey).ToString();

            }
            catch
            {
                keyExists = false;
            }

            return keyExists;
        }

        public static object GetValue(string key, string valueName, RegistryKey baseGroupKey)
        {
            object value = null;
            RegistryKey readKey = null;

            readKey = baseGroupKey.OpenSubKey(key, true);

            if (readKey != null)
                value = readKey.GetValue(valueName);


            if (readKey != null)
                readKey.Close();


            return value;
        }

        public static void SetValue(string key, RegistryKey baseGroupKey, string valueName, object objectValue, RegistryValueKind valueType)
        {
            RegistryKey createKey = null;

            createKey = baseGroupKey.OpenSubKey(key, true);
            createKey.SetValue(valueName, objectValue, valueType);

            if (createKey != null)
                createKey.Close();
        }

        /// <summary>
        /// Get the Product key
        /// </summary>
        /// <param name="productName">Product Name</param>
        /// <returns></returns>
        public static RegistryKey GetProductKey(string productName)
        {
            RegistryKey productKey = null;
            string[] softwareInstalled;

            RegistryKey rootKey = Registry.LocalMachine.OpenSubKey(REGISTRY_UNINSTALL_PATH);

            if (rootKey != null)
            {
                softwareInstalled = rootKey.GetSubKeyNames();

                foreach (string key in softwareInstalled)
                {
                    RegistryKey subKey = rootKey.OpenSubKey(key);

                    if (subKey != null)
                    {
                        object displayName = subKey.GetValue("DisplayName");

                        if (displayName != null && displayName.ToString().ToUpper() == productName.ToUpper())
                        {
                            productKey = subKey;
                            break;
                        }
                    }

                    subKey.Close();
                }

                rootKey.Close();
            }

            return productKey;
        }

        /// <summary>
        /// Get all Installed Information
        /// </summary>
        /// <param name="system">System Id</param>
        /// <returns>Installed Information</returns>
        public static InstalledInformation GetInstalledInformation(string system)
        {
            if (string.IsNullOrEmpty(system))
                throw new ArgumentNullException("system");

            InstalledInformation information = new InstalledInformation();

            var keys = Registry.LocalMachine.OpenSubKey(REGISTRY_UNINSTALL_PATH + system);

            if (keys == null)
                return null;

            information.DisplayName = keys.GetValue("DisplayName").ToString();
            information.UninstallString = keys.GetValue("UninstallString", information.UninstallString).ToString();
            information.DisplayIcon = keys.GetValue("DisplayIcon", information.DisplayIcon).ToString();
            information.InstallLocation = keys.GetValue("InstallLocation", information.InstallLocation).ToString();
            information.InstallSource = keys.GetValue("InstallSource", information.InstallSource).ToString();
            information.ParametersFilePath = keys.GetValue("ParametersFilePath", information.ParametersFilePath).ToString();
            information.DisplayVersion = keys.GetValue("DisplayVersion", information.DisplayVersion).ToString();
            information.NoModify = keys.GetValue("NoModify").ToString() == "1" ? true : false;
            information.NoRemove = keys.GetValue("NoRemove").ToString() == "1" ? true : false;
            information.NoRepair = keys.GetValue("NoRepair").ToString() == "1" ? true : false;

            return information;
        }

        /// <summary>
        /// Checks whether there is information about the installation or uninstallation
        /// </summary>
        /// <param name="system">System Id</param>
        /// <returns>True/False if exists or not</returns>
        public static bool HasInstalledInformation(string system)
        {
            if (string.IsNullOrEmpty(system))
                throw new ArgumentNullException("system");

            return Registry.LocalMachine.OpenSubKey(REGISTRY_UNINSTALL_PATH + system) != null;
        }

        /// <summary>
        /// Add into Registry the Installed Information
        /// </summary>
        /// <param name="system">System Id</param>
        /// <param name="information">The Informations</param>
        public static void AddInstalledInformation(string system, InstalledInformation information)
        {
            if (string.IsNullOrEmpty(system))
                throw new ArgumentNullException("system");

            if (information == null)
                throw new ArgumentNullException("information");

            string regKey = REGISTRY_UNINSTALL_PATH + system;
            RegistryKey key = Registry.LocalMachine.CreateSubKey(regKey);

            if (!string.IsNullOrEmpty(information.DisplayName))
                key.SetValue("DisplayName", information.DisplayName);
            if (!string.IsNullOrEmpty(information.UninstallString))
                key.SetValue("UninstallString", information.UninstallString);
            if (!string.IsNullOrEmpty(information.DisplayIcon))
                key.SetValue("DisplayIcon", information.DisplayIcon);
            if (!string.IsNullOrEmpty(information.InstallLocation))
                key.SetValue("InstallLocation", information.InstallLocation);
            if (!string.IsNullOrEmpty(information.InstallSource))
                key.SetValue("InstallSource", information.InstallSource);
            if (!string.IsNullOrEmpty(information.ParametersFilePath))
                key.SetValue("ParametersFilePath", information.ParametersFilePath);
            if (!string.IsNullOrEmpty(information.DisplayVersion))
                key.SetValue("DisplayVersion", information.DisplayVersion);

            key.SetValue("NoModify", (information.NoModify ? 1 : 0));
            key.SetValue("NoRemove", (information.NoRemove ? 1 : 0));
            key.SetValue("NoRepair", (information.NoRepair ? 1 : 0));
        }

        /// <summary>
        /// Remove all Installed Information
        /// </summary>
        /// <param name="system">System Id</param>
        public static void RemoveInstalledInformation(string system)
        {
            if (string.IsNullOrEmpty(system))
                throw new ArgumentNullException("system");

            string regKey = REGISTRY_UNINSTALL_PATH + system;

            if (Registry.LocalMachine.OpenSubKey(regKey) != null)
                Registry.LocalMachine.DeleteSubKeyTree(regKey);
        }
    }
}
